import mongoose,{Schema,Model,Document,HookNextFunction} from 'mongoose';
import validator from 'validator';
import {UserPayload} from '../typings/jwt';
import jwt from 'jsonwebtoken'
import configs from '../config'
import bcrypt from 'bcryptjs';

export interface IUserDocument extends Document{
    username: string,
    password: string,
    avatar: string,
    email: string,
    generateToken: ()=>string,
    _doc: IUserDocument
}

const UserSchema: Schema<IUserDocument>=new Schema({
    username:{
        type: String,
        required: [true,'用户名不能为空'],
        minLength: [true,'最小长度不能少于6位'],
        maxLength: [true,'最大长度不能大于12位'],
    },
    password: String,
    avatar: String,
    email:{
        type: String,
        validate: {
            validator: validator.isEmail
        },
        trim: true
    },
},{
    timestamps: true,
    toJSON: {
        transform: (_doc:any,result:any,options: any)=>{
            result.id= result._id,
            delete result._id;
            delete result.__v;
            delete result.password;
            delete result.createdAt;
            delete result.updatedAt;
            return result;
        }
    }
});

UserSchema.methods.generateToken =function():string{
    let payload: UserPayload= {id: this._id};
    return jwt.sign(payload,configs.JWT_SECRET_KEY,{expiresIn: '7d'});
}

UserSchema.pre<IUserDocument>("save",async function(next:HookNextFunction){
    //产生密码hash当密码有更改的时候(或者是新密码)
    if (!this.isModified('password')) return next();
    try{
        this.password= await bcrypt.hash(this.password,10);
        next();
    }catch(e){
        next(e);
    }
})

UserSchema.static('login',async function(this: any,username: string,password: string){
    let user:IUserDocument | null = await this.model("User").findOne({username});
    if(user){
        const matched= await bcrypt.compare(password,user.password);
        if(matched) return user;
        else return null;
    }
    return null;
})

interface IUserModel<T extends Document> extends Model<T>{
    login: (username:string,password:string)=>IUserDocument | null
}

export const User:IUserModel<IUserDocument>=mongoose.model<IUserDocument,IUserModel<IUserDocument>>("User",UserSchema);